package com.fsh.anime.wx.service.impl;

import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.fsh.anime.model.pojos.User;
import com.fsh.anime.service.UserService;
import com.fsh.anime.utils.JwtUtil;
import com.fsh.anime.wx.adapter.TextBuilder;
import com.fsh.anime.wx.service.WXMsgService;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.bean.WxOAuth2UserInfo;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class WXMsgServiceImpl implements WXMsgService {

    @Autowired
    private UserService userService;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Value("${wx.mp.callback}")
    private String callBack;

    private static final String  URL="https://open.weixin.qq.com/connect/oauth2/authorize?appid=%s&redirect_uri=%s&response_type=code&scope=%s&state=STATE#wechat_redirect";

    private String fromUser;
    /**
     * 对用户
     */
    private String toUser;

    /**
     * 用户扫码处理（已关注和未关注）
     *
     * @param wxMpXmlMessage
     * @param wxMpService
     */
    @Override
    public WxMpXmlOutMessage scan(WxMpXmlMessage wxMpXmlMessage, WxMpService wxMpService) {
        fromUser=wxMpXmlMessage.getFromUser(); // 微信官方
        toUser=wxMpXmlMessage.getToUser(); //扫码人
        //获取openId
        String openId = wxMpXmlMessage.getFromUser();
        //查询该用户是否已经注册过并授权过。（特征为：既有openId，也有昵称和头像）
        User user = userService.selectByOpenId(openId);
        //1.已注册且授权
        if (Objects.nonNull(user) && StrUtil.isNotBlank(user.getAvatar())) {
            //说明已经注册并授权过了（只有授权过的用户才能查询到名字和头像）
            // 走登陆成功的逻辑
            return scanLoginSuccess(user, "登陆成功", toUser,fromUser);
        }
        //2.用户未注册，那就先注册。
        if (Objects.isNull(user)) {
            User u = new User();
            u.setOpenId(openId);
            //注册完后数据库的用户信息只有 openId
            userService.register(u);
        }


        //3.剩下的是已注册完，但是没有授权！没有授权就拿不到用户的头像和名字等信息。那就推送链接让用户授权
        //构建URL，拼接串。
        // 其中第二个参数为地址就是WxPortalController中的一个接口，靠这个重定向接口获取code
        String formatURL = String.format(URL, wxMpService.getWxMpConfigStorage().getAppId(),
                URLEncoder.encode(callBack + "/api/wx/portal/public/callBack"),
                "snsapi_userinfo");
        //返回一些提示信息。
        return TextBuilder.build("你好，动漫星球欢迎您。<a href=\"" + formatURL + "\">请登录</a>"
                , wxMpXmlMessage, wxMpService);
    }

    /**
     * 扫码登录成功
     */
    private WxMpXmlOutMessage scanLoginSuccess(User user, String msg,String toUser,String fromUser) {
        // redis中存储token
        String token = getToken(user);
        stringRedisTemplate.opsForValue().set("wx:token", token, 5, TimeUnit.MINUTES);
        return TextBuilder.build(msg,toUser,fromUser);
    }


    private String getToken(User user) {
        //封装自定义信息
        Map<String, Object> claims = new HashMap<>();
        claims.put("id", user.getId());
        claims.put("role", user.getRole());
        //使用JWT工具类，生成身份令牌
        String token = JwtUtil.getToken(claims);
        return token;
    }

    /**
     * 拿到用户信息后，授权，保存用户的信息到数据库
     *
     * @param userInfo
     */
    @Override
    public void authorize(WxOAuth2UserInfo userInfo) {
        String openId=userInfo.getOpenid();
        //通过openId，更新用户的信息，补上名字和头像等
        User user = userService.selectByOpenId(openId);
        if (StrUtil.isBlank(user.getAvatar())){
            User u=new User();
            u.setId(user.getId());
            u.setName(userInfo.getNickname());
            u.setAvatar(userInfo.getHeadImgUrl());
            u.setRole("_user");
            //数据库中设置的name唯一，所以这里可能会出现名字重复(虽然概率很低)
            try{
                userService.updateById(u);
            }catch (DuplicateKeyException e){
                log.info("WXMsgServiceImpl.authorize===>user插入数据库，name重复。{}",e.getMessage());
                //设置uuid
                u.setName(RandomUtil.randomString(10));
                userService.updateById(u);
            }
        }
        //用户信息授权完后， 走 登陆成功的方法逻辑
        scanLoginSuccess(user,"登陆成功",toUser,fromUser);
    }

}
